<?php
/**
 * 读取全局配置文件
 * @param string $name
 * @return string
 */
function getProperty(string $name):string{
    $a=@readPropertiesFile("global","prop",RETURN_FORMAT_array)[$name];
    if ($a){
        return $a;
    }else{
        return "";
    }
}

/**
 * 返回指定配置文件的内容
 * @param string $name 文件名
 * @param string $format 文件格式（后缀），不加“.”
 * @param int $return_format 指定返回格式
 * @return string|array
 */
function readPropertiesFile(string $name,string $format="prop",int $return_format=RETURN_FORMAT_STRING){
    $a=@file_get_contents(CONFIG_PATH.$name.".".$format);/*读取文件*/
    $a=str_replace("\r","\n",$a);/*统一换行符*/
    if($return_format==RETURN_FORMAT_STRING){/*通过字符串形式返回*/
        return$a??"";
    }elseif($return_format==RETURN_FORMAT_JSON){/*文件为JSON时返回对应的数组*/
        return json_decode($a,true)??"";
    }elseif($return_format==RETURN_FORMAT_array){/*文件为Prop时返回对应的数组*/
        $t=[];
        $a=explode("\n",$a);
        /*读取每一行*/
        for($i=0;$i<count($a);$i++){
            /*每行开头不为#，#表示注释；并且不是空行*/
            if(substr($a[$i],0,1)!="#"&&strpos($a[$i],"=")){
                $b=explode("=",$a[$i]);
                $t[$b[0]]=$b[1];
            }
        }
        return$t??[];
    }else{
        return"";
    }
}

/**
 * 获取请求路径
 * @return string 请求路径
 */
function getPath():string{
    $a=$_SERVER["QUERY_STRING"];/*读取URL中“/?”后的内容*/
    $i=strpos($a,"&");/*获取&的位置*/
    $j=strpos($a,"?");/*获取?的位置*/
    /*-----对连接符的判断-----*/
    if ($i&&$j&&$j<$i){
        $i=$j;/*?在&前时取?的位置*/
    }elseif(!$i&&$j){
        $i=$j;/*只存在?则取问号*/
    }elseif(!$i&&!$j){
        $i=-1;/*?和&都不存在*/
    }
    $enableStatic = getProperty("enableStatic");
    if (substr($a,$i-1,1)=="/"){
        $b = ($enableStatic=="1"?"":"?") . substr($a,0,$i-1).substr($a,$i);
        header("Location:$b");
    }
    if ($i==-1&&substr($a,strlen($a)-1)=="/"){
        $b = ($enableStatic=="1"?"":"?") . substr($a,0,strlen($a)-1);
        header("Location:$b");
    }
    if($i>=0){
        $a=substr($a,1,$i-1);/*存在?或&时取前面部分*/
    }else{
        $a=substr($a,1);/*不存在时删除前面的“/”*/
    }
    if (strlen($a)==0){$a="index";}/*路径为空时为index*/
    if(substr($a,0,1)=="/"){$a=substr($a,1);}/*路径开头为“/”时去除*/
    $a=str_replace("/","_",$a);
    return $a;
}

/**
 * 加载错误页面
 * @param string $title 错误页面标题
 * @param string $message 错误消息
 * @param bool $die 是否终止程序执行
 */
function loadErrorPage(string $title, string $message,bool $die = true){
    echo "<head><title>$title</title><meta name='viewport' content='width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no' /><meta charset='UTF-8'></head>".str_replace("{ERROR_CONTENT}",$message,str_replace("{ERROR_TITLE}",$title,file_get_contents(COMMON_HTML_PATH."error.html")));
    if ($die){
        writeLog("Error",$message);
        die();
    }else{
        writeLog("Info",$message);
    }
}

/**
 * 获取当前域名绑定的别名
 * @return string 返回别名
 */
function getBindName():string{
    $enable=getProperty("enableDomains");
    if($enable==0){
        return "default";
    }
    $a=readPropertiesFile("domains","json",RETURN_FORMAT_JSON);/*读取域名绑定列表*/
    $c="";/*需要执行的别名*/
    for ($i=0;$i<count($a);$i++){
        $b=$a[$i]["host"];
        if (in_array($_SERVER["HTTP_HOST"],$b)){/*域名被绑定*/
            $c=$a[$i]["name"];/*指定执行的别名*/
        }
    }
    return$c;
}

/**
 * 获取当前域名是否启用SSL
 *
 * @return boolean 是否启用SSL
 */
function getBindSSL():bool{
    $a=readPropertiesFile("domains","json",RETURN_FORMAT_JSON);/*读取域名绑定列表*/
    $c="";/*需要执行的别名*/
    for ($i=0;$i<count($a);$i++){
        $b=$a[$i]["host"];
        if (in_array($_SERVER["HTTP_HOST"],$b)){/*域名被绑定*/
            $c=$a[$i]["ssl"];/*SSL*/
        }
    }
    return$c??false;
}

/**
 * 获取浏览器类型
 * IURT_Sean提供支持
 *
 * @return string 浏览器名称
 */
function GetBrowser():string{
    $a=$_SERVER['HTTP_USER_AGENT'];
    if(!empty($a)){
        if(preg_match('/MSIE/i',$a))$b='MSIE';
        elseif (preg_match('/Firefox/i',$a))$b='Firefox';
        elseif (preg_match('/Chrome/i',$a))$b='Chrome';
        elseif (preg_match('/Safari/i',$a))$b='Safari';
        elseif(preg_match('/Opera/i',$a))$b='Opera';
        else$b='Other';
        return$b;
    }else{
        return"获取浏览器信息失败！";
    }
}


   /**
 * 加载指定HTML
 * @param string $name 文件名
 * @param bool $custom 是否为自定义路径
 * @param array $args 页面参数
 */
function loadHtml(string$name,bool$custom=false,array$args=[]){
    $fn=$custom?$name:HTML_PATH."$name.html";/*文件路径*/
    $a=str_replace("\r","\n",file_get_contents($fn));/*统一换行符*/
    $fl=str_replace("<!--","",str_replace("-->","",explode("\n",$a)[0]));/*读取首行配置*/
    $t=[];
    foreach(explode(";",$fl)as$item){/*读取每一项配置*/
        if($item){
            $e=explode("=",$item);/*将配置名和值分开*/
            $t[$e[0]]=@$e[1];
        }
    }
    $fe="";/*头部增加的内容*/
    $bfe="";/*HTML中追加的内容*/
    $after="";/*结尾追加的内容*/
    $h=file_get_contents(HTML_PATH."head.html");/*加载头部文件*/
    $h=str_replace("{TITLE}",$t["title"],$h);/*替换标题*/
    foreach(explode(",",$t["js"])as$item) {/*加载JS*/
        if($item){
            if ($item==$name){
                $after.="<script>".file_get_contents(JS_PATH.$item.".js")."</script>";/*和当前页面同名时追加到页面中*/
            }else{
                $bfe.="<script src='".linkProcess("{LINK_file}")."&type=js&name=$item'></script>";/*和当前页面不同名时追加到头部*/
            }
        }
    }
    foreach (explode(",",$t["css"])as$item){/*加载CSS*/
        if($item){
            if($item==$name){
                /*echo $item." ".$name." yes<br>";*/
                $after.="<style>".file_get_contents(CSS_PATH.$item.".css")."</style>";/*和当前页面同名时追加到页面中*/
            }else{
                /*echo $item." ".$name." no<br>";*/
                $fe.="<link rel='stylesheet' href='".linkProcess("{LINK_file}")."&type=css&name=$item'>";/*和当前页面不同名时追加到头部*/
            }
        }
    }
    if(@$t["mobile"]=="yes"){/*开启手机端尺寸优化*/
        $h.='<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />';
    }
    $h=str_replace("{FILES}",$fe,$h);/*将处理完的内容追加到头部中*/
    for($i=0;$i<count($args);$i++){
        $k=array_keys($args)[$i];
        $v=$args[$k];
        $a=str_replace("{".$k."}",$v,$a);/*替换指定内容(args)*/
    }
    $a=str_replace("{JS}",$bfe,$a);
    echo linkProcess($h);/*处理多余特殊引用并输出头部*/
    echo str_replace("<!--$fl-->","",linkProcess($a));/*处理并输出主体部分*/
    echo linkProcess($after);/*处理并追加后部内容*/
}

/**
 * 特殊引用处理
 *
 * @param string $input 输入内容
 * @return string 返回内容
 */
function linkProcess(string$input):string{
    $enableStatic=getProperty("enableStatic")==1;
    $index=0;
    $args_index=0;
    $args_list=[];
    $left=false;/*是否遇到{*/
    $special_list=[/*特殊引用列表*/
        "ICON"=>@file_get_contents(FILES_PATH."icon"),/*网页图标，必须为base64格式*/
        "VERSION"=>@file_get_contents(FILES_PATH."version")/*网站版本*/
    ];
    for($i=0;$i<strlen($input);$i++){
        $t=substr($input,$i,1);
        if($t=="{"){
            $left=true;
            continue;
        }
        if($t=="}"){
            $left=false;
            $args_index++;
        }
        if($left){
            if($t==" "||$t=="\r"||$t=="\n"){/*后方为空格或换行，通常为JS代码段结束，防止识别错误*/
                $left=false;
                continue;
            }
            @$args_list[$args_index].=$t;/*追加参数*/
        }
    }
    foreach ($args_list as $item) {
        if(strpos($item,"_")){/*是否有分隔符*/
            $l=explode("_",$item);
            switch (strtoupper($l[0])){/*根据参数第一部分判断类型*/
                case"IMG":/*图片类型，{IMG_NAME_EXT}，文件名中不能存在“_”*/
                    // $input=str_replace("{".$item."}",IMG_PATH.$l[1].".".$l[2],$input);
                    $input=str_replace("{".$item."}",linkProcess("{LINK_file}").(inPhar()?"?":":")."type=".$l[2]."&name=".$l[1],$input);
                    break;
                case"JS":/*JS类型，{JS_NAME}*/
                    $input=str_replace("{".$item."}",JS_PATH.$l[1].".js",$input);
                    break;
                case"CSS":/*CSS类型，{CSS_NAME}*/
                    $input=str_replace("{".$item."}",CSS_PATH.$l[1].".css",$input);
                    break;
                case "LINK":/*超链接类型，{LINK_PATH}*/
                    $input=str_replace("{".$item."}",($enableStatic?"/":"./?/").substr($item,strpos($item,"_")+1),$input);
                    break;
            }
        }else{/*没有分隔符时从特殊引用列表中寻找*/
            if(isset($special_list[$item])){
                $input=str_replace("{".$item."}",$special_list[$item],$input);/*找到时替换*/
            }
        }
    }
    return $input;
}

/**
 * 发送邮件
 *
 * @param string $title 邮件标题
 * @param string $content 邮件内容
 * @param string $address 邮箱地址
 * @param string $name 名字
 * @return bool 成功状态
 */
function sendMail(string$title,string$content,string$address,string$name):bool{
    require CORE_PATH."mail/PHPMailerAutoload.php";
    $config = readPropertiesFile("mail","prop",RETURN_FORMAT_array);
    $mail = new PHPMailer(false);
    $mail->isSMTP();
    $mail->Host = $config["smtp"];
    $mail->SMTPAuth=true;
    $mail->Username=$config["username"];
    $mail->Password=$config["password"];
    try{
        $mail->setFrom($config["username"],$name);
    }catch(phpmailerException$e){}
    $mail->addAddress($address);
    $mail->CharSet="UTF-8";
    $mail->Subject=$title;
    $mail->Body=str_replace("{ERROR_TITLE}",$title,
                str_replace("{ERROR_CONTENT}",$content,
            file_get_contents(COMMON_HTML_PATH."error.html")
        )
    );
    $mail->AltBody = $title;
    try{
        if($mail->send()){
            return true;
        }else{
            /* echo $mail->ErrorInfo; */
            return false;
        }
    }catch(phpmailerException$e){}
}

/**
 * 连接数据库
 *
 * @return mysqli 数据库对象
 */
function connectDB():mysqli{
    writeLog("Info","读取MySQL数据库配置文件");
    $config=readPropertiesFile("mysql","prop",RETURN_FORMAT_array);
    $host=$config["hostname"];
    $port=$config["port"];
    $user=$config["username"];
    $pass=$config["password"];
    $name=$config["database"];
    writeLog("Info","尝试连接数据库");
    return mysqli_connect($host,$user,$pass,$name,$port);
}

/**
 * 返回是否被打包进phar中
 * @return bool 是否被打包
 */
function inPhar():bool{
    return!is_dir("src");
}

/**
 * 返回操作系统类型
 *
 * @return string Windows/Linux
 */
function getOS():string{
    $a=php_uname("s");
    if(strpos($a,"Windows")>=0)return"Windows";
    if(strpos($a,"Linux")>=0)return"Linux";
    return"";
}

/**
 * 写入日志
 *
 * @param string $name 日志行标题/名称
 * @param string $content 日志内容
 * @return void
 */
function writeLog(string$name,string$content){
    @mkdir(GLOBAL_LOG_PATH);
    @mkdir(LOG_PATH);
    $host = str_replace(":","-",$_SERVER["REMOTE_ADDR"]);
    @mkdir(LOG_PATH.$host);
    $file = LOG_PATH.$host."/".date("Y-m-d").".log";
    touch($file);
    $time = date("H:i:s");
    $a=file_get_contents($file);
    $a.="[$time - $name] (".getBindName()." ".getPath().") $content\n";
    file_put_contents($file,$a);
}

/* 请求参数模块 */
/**
 * 获取get请求参数
 *
 * @param string $name 参数名
 * @return string 内容
 */
function args_get(string$name):string{
    return@$_GET[$name]??"";
}

/**
 * post请求参数
 *
 * @param string $name 参数名
 * @return string
 */
function args_post(string$name):string{
    return@$_POST[$name]??"";
}

/**
 * 通用请求模式参数
 *
 * @param string $name 参数名称
 * @return string 内容
 */
function args_request(string$name):string{
    return@$_REQUEST[$name]??"";
}

/* COOKIE处理模块 */
/**
 * 获取cookie信息
 *
 * @param string $name cookie名称
 * @return string 内容
 */
function cookie_get(string$name):string{
    return $_COOKIE[$name]??"";
}

/**
 * 设置cookie信息
 *
 * @param string $name cookie名称
 * @param string $value cookie内容
 * @return void
 */
function cookie_set(string$name,string$value){
    setcookie($name,$value);
}

/**
 * 删除cookie信息
 *
 * @param string $name cookie名称
 * @return void
 */
function cookie_delete(string$name){
    setcookie($name);
}

/* SESSION处理模块 */
/**
 * 获取session信息
 *
 * @param string $name session名称
 * @return string 内容
 */
function session_get(string$name):string{
    return $_SESSION[$name]??"";
}
/**
 * 设置session信息
 *
 * @param string $name session名称
 * @param string $value session内容
 * @return void
 */
function session_set(string$name,string$value){
    $_SESSION[$name]=$value;
}
/**
 * 删除session信息
 *
 * @param string $name session名称
 * @return void
 */
function session_delete(string$name){
    unset($_SESSION[$name]);
}

/* 字符串加密模块 */
/*-----依赖代码，请勿修改里面的内容，防止出现不可预知的问题-----*/class __a{public static function _a(string$_a,string$_b,bool$_c=false):string{$a=base64_encode($_a);$b=str_split($a);$c="";foreach($b as$m){$x_a=ord($m);$x_b=127-$x_a;$x_c=dechex($x_b);if(strlen($x_c)==1){$x_c="0".$x_c;}$c.=$x_c;}$d=substr(hash("sha256",$_b),0,strlen($_b));$c_a=str_split($c);$d_a=str_split($d);$e="";$index=0;foreach($c_a as$item){$v_a=$item;$v_b=$d_a[$index++%count($d_a)];$v_c=decbin(ord($v_a)+ord($v_b));if(strlen($v_c)==7){$v_c="0".$v_c;}$e.=$v_c;}$f=decbin(rand(0,127));switch(strlen($f)){case 0:$f="00000000";break;case 1:$f="0000000".$f;break;case 2:$f="000000".$f;break;case 3:$f="00000".$f;break;case 4:$f="0000".$f;break;case 5:$f="000".$f;break;case 6:$f="00".$f;break;case 7:$f="0".$f;break;}$g="";$h=str_split($e);$x=str_split($f);for($i=0;$i<count($h);$i++){$i_a=$h[$i];$i_b=$x[$i%8];$i_c=$i_a===$i_b?"0":"1";$h[$i]=$i_c;}$t="";for($i=0;$i<count($h);$i++){$t.=$h[$i];}$t.=$f;$h=str_split($t);for($i=0;$i<count($h);$i++){$a=chr(rand(97,122));$A=chr(rand(65,90));if($h[$i]==0){$g.=$a;}elseif($h[$i]==1){$g.=$A;}}if($_c){return$g;}else{echo$g;}return"";}public static function _b(string$_a,string$_b,bool$_c=false):string{$a=str_split($_a);$b="";for($i=0;$i<count($a);$i++){$i_a=ord($a[$i]);$_a=97;$_z=122;$_A=65;$_Z=90;if($i_a<=$_z&&$i_a>=$_a){$b.="0";}elseif($i_a<=$_Z&&$i_a>=$_A){$b.="1";}}$c=substr($b,0,strlen($b)-8);$d=substr($b,strlen($b)-8,8);$c_a=str_split($c);$c_b=str_split($d);$e="";for($i=0;$i<count($c_a);$i++){$i_a=$c_a[$i];$i_b=$c_b[$i%8];$i_c=$i_a===$i_b?"0":"1";$e.=$i_c;}$f=str_split($e,8);$g=str_split(substr(hash("sha256",$_b),0,strlen($_b)));$h="";for($i=0;$i<count($f);$i++){$x_a=bindec($f[$i]);$x_b=ord($g[$i%count($g)]);$x_c=chr($x_a-$x_b);$h.=$x_c;}$m=str_split($h,2);$n="";for($i=0;$i<count($m);$i++){$i_a=chr(127-hexdec($m[$i]));$n.=$i_a;}$o=base64_decode($n);if($_c){return$o;}else{echo$o;return"";}}}
/**
 * 加密字符串
 * @param string $string 需要加密的数据
 * @param string $secret 加密用的密钥
 * @param bool $return 是否返回，默认不返回直接输出
 * @return string 返回加密后的数据
 */
function string_encode(string $string,string $secret,bool $return=false):string{
    return __a::_a($string,$secret,$return);
}

/**
 * 解密字符串
 * @param string $string 需要解密的数据
 * @param string $secret 解密用的密钥
 * @param bool $return 是否返回，默认不返回直接输出
 * @return string 返回解密后的数据
 */
function string_decode(string $string,string $secret,bool $return=false):string{
    return __a::_b($string,$secret,$return);
}